package com.ruoyi.finance.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.ProcuredOrders;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.depot.domain.Receipt;
import com.ruoyi.depot.mapper.ReceiptMapper;
import com.ruoyi.finance.domain.*;
import com.ruoyi.finance.domain.dto.VendorMonetaryDTO;
import com.ruoyi.finance.domain.vo.PaymentMasterVo;
import com.ruoyi.finance.domain.vo.PaymentVoucherLogVo;
import com.ruoyi.finance.domain.vo.PaymentVoucherVo;
import com.ruoyi.finance.mapper.*;
import com.ruoyi.finance.mapper.vo.PaymentMasterVoMapper;
import com.ruoyi.finance.service.IPaymentRequestService;
import com.ruoyi.finance.service.IPaymentVoucherService;
import com.ruoyi.procured.domain.*;
import com.ruoyi.procured.mapper.*;
import com.ruoyi.procured.service.IPaymentRequestProcessService;
import com.ruoyi.procured.service.IProcuredPlanProcessService;
import com.ruoyi.system.mapper.SysMenuMapper;
import com.ruoyi.template.domain.TemplateDetail;
import com.ruoyi.template.mapper.TemplateMapper;
import com.ruoyi.template.service.TemplateDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.NumberUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.ruoyi.common.utils.PageUtils.startPage;

@Service
public class PaymentVoucherImpl implements IPaymentVoucherService
{

    @Autowired
    private PaymentRequestMapper paymentRequestMapper;
    @Autowired
    private IPaymentRequestService paymentRequestService;
    @Autowired
    private PaymentVoucherMapper paymentVoucherMapper;
    @Autowired
    private PaymentVoucherLogMapper paymentVoucherLogMapper;
    @Autowired
    private PaymentMasterMapper paymentMasterMapper;
    @Autowired
    private PaymentMasterVoMapper paymentMasterVoMapper;
    @Autowired
    private PaymentWaterReceiptMapper paymentWaterReceiptMapper;
    @Autowired
    private PaymentWaterReceiptVoucherMapper paymentWaterReceiptVoucherMapper;
    @Autowired
    private IPaymentRequestProcessService paymentRequestProcessService;
    @Autowired
    private ProcuredOrdersMapper procuredOrdersMapper;
    @Autowired
    private PaymentRequestLogMapper paymentRequestLogMapper;
    @Autowired
    private ProcuredPlanLogMapper procuredPlanLogMapper;
    @Autowired
    private ProcuredPlanMapper procuredPlanMapper;
    @Autowired
    private SysMenuMapper sysMenuMapper;
    @Autowired
    private TemplateMapper templateMapper;
    @Autowired
    private TemplateDetailService templateDetailService;
    @Autowired
    private IProcuredPlanProcessService procuredPlanProcessService;
    @Autowired
    private ProcuredProductMapper procuredProductMapper;

    @Autowired
    private ReceiptMapper receiptMapper;
    /**
     * 付款单状态（0未核准，1未过账，2已过账，3已驳回，4付款中）
     */
    public static final String PAYMENT_VOUCHER_STATUS_NOVOUCHER = "0";
    /**
     * 付款单状态（0未核准，1未过账，2已过账，3已驳回，4付款中）
     */
    public static final String PAYMENT_VOUCHER_STATUS_NOPAY = "1";
    /**
     * 付款单状态（0未核准，1未过账，2已过账，3已驳回，4付款中）
     */
    public static final String PAYMENT_VOUCHER_STATUS_ISPAY = "2";
    /**
     * 付款单状态（0未核准，1未过账，2已过账，3已驳回，4付款中）
     */
    public static final String PAYMENT_VOUCHER_STATUS_ISREJECT = "3";
    /**
     * 付款单状态（0未核准，1未过账，2已过账，3已驳回，4付款中）
     */
    public static final String PAYMENT_VOUCHER_STATUS_ISLOCK = "4";
    /**
     * 申请付款状态（0未付款，1已生成付款单，2已过账）
     */
    public static final String PAYMENT_STATUS_ISVOUCHER = "1";
    /**
     * 申请付款状态（0未付款，1已生成付款单，2已过账）
     */
    public static final String PAYMENT_STATUS_ISPAY = "2";
    /**
     * 生成付款单
     */
    @Override
    @Transactional
    public void voucherPaymentRequest(List<String> paymentRequestIds, String nickName) {

        //检查是否都为已审核状态，未付款
        paymentRequestService.CheckPaymentRequestStatus(paymentRequestIds,"1","非已审核、非未付款","0");
        //检查是否生成了付款单
        boolean exists = checkPaymentVoucher(paymentRequestIds);
        if(exists){
            throw new ServiceException("所选记录含有已生成付款单记录，请重新选择。");
        }
        String paymentRequestIdOne = paymentRequestIds.get(0);
        //保存付款单主表
        PaymentMaster pm =  savePaymentMasterByPaymentRequestId( paymentRequestIdOne, nickName);
        //保存付款单明细
        savePaymentVoucherByPaymentRequestId(paymentRequestIds,nickName,pm);
    }

    /**
     * 查询付款单列表
     */
    @Override
    public List<PaymentMasterVo> selectPaymentMasterVotList(PaymentMasterVo paymentMasterVo){

        //1：根据子表条件，先查出所有满足条件的付款单
        PaymentVoucherVo pvo = new PaymentVoucherVo();
        pvo.setPaymentMasterStatus(paymentMasterVo.getPaymentMasterStatus());
        pvo.setDeleteStatus(paymentMasterVo.getDeleteStatus());
        pvo.setVendorId(paymentMasterVo.getVendorId());
        pvo.setStartTime(paymentMasterVo.getStartTime());
        pvo.setEndTime(paymentMasterVo.getEndTime());
        pvo.setPaymentMasterStatus(paymentMasterVo.getPaymentMasterStatus());
        pvo.setSelect(paymentMasterVo.getSelect());
        pvo.setUnknown(paymentMasterVo.getUnknown());

        List<PaymentVoucherVo> voucherList = paymentMasterVoMapper.selectPaymentVouchersByMasterIds(pvo);

        // 2：提取满足条件的主表ID
        List<String> masterIds = voucherList.stream()
                .map(PaymentVoucherVo::getPaymentMasterId)
                .distinct()
                .collect(Collectors.toList());

        if (masterIds.isEmpty()) {
            return Collections.emptyList(); // 没有主表符合条件
        }


        // 3：分页查询主表（仅查符合子表条件的主表ID）
        paymentMasterVo.setMasterIds(masterIds); // 新增字段，需要你在mapper里支持
        startPage();
        // 1. 先分页查询主表数据
        List<PaymentMasterVo> masterList = paymentMasterVoMapper.selectPaymentMasterPageList(paymentMasterVo);
        if (masterList == null || masterList.isEmpty()) {
            return masterList;
        }

        // 4. 将子表数据按 paymentMasterId 分组
        Map<String, List<PaymentVoucherVo>> grouped = voucherList.stream()
                .collect(Collectors.groupingBy(PaymentVoucherVo::getPaymentMasterId));

        // 5. 将子表数据塞进主表对应的字段中，并移除没有子表的主表
        masterList.removeIf(master -> {
            List<PaymentVoucherVo> vouchers = grouped.get(master.getPaymentMasterId());
            if (vouchers == null || vouchers.isEmpty()) {
                return true; // 移除没有子表的主表
            }
            master.setPaymentVouchers(vouchers);
            return false;
        });
        return masterList;
    }
    /**
     * 核准付款单
     */
    @Override
    @Transactional
    public void approvedPaymentVoucher(List<String> paymentVoucherIds, String nickName) {
        //检查是否为【未核准】状态
        CheckPaymentVoucherStatus(paymentVoucherIds,PAYMENT_VOUCHER_STATUS_NOVOUCHER,"非未核准");
        //更新状态：未核准=》未过账
        LambdaUpdateWrapper<PaymentVoucher> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(PaymentVoucher::getPaymentVoucherId,paymentVoucherIds)
                .set(PaymentVoucher::getPaymentVoucherStatus,PAYMENT_VOUCHER_STATUS_NOPAY)
                .set(PaymentVoucher::getApprovedBy,nickName)
                .set(PaymentVoucher::getApprovedTime,DateUtils.getNowDate())
                .set(PaymentVoucher::getUpdateBy,nickName)
                .set(PaymentVoucher::getUpdateTime,DateUtils.getNowDate());
        paymentVoucherMapper.update(null,updateWrapper);
        //插入日志
        paymentVoucherIds.stream()
                .forEach(paymentVoucherId -> {
                    //生成付款单日志
                    savePaymentVoucherLog(paymentVoucherId,"核准通过", nickName,"");
        });
        //生成水单并关联申请单
        savePaymentWaterReceipt(paymentVoucherIds,nickName);

        //更新付款单主表状态
        updatePaymentMasterStatus(paymentVoucherIds);
    }
    /**
     * 批量核准（单独付款）
     */
    @Override
    @Transactional
    public void approvedPaymentVoucherOnly(List<String> paymentVoucherIds, String nickName) {
        //检查是否为【未核准】状态
        CheckPaymentVoucherStatus(paymentVoucherIds,PAYMENT_VOUCHER_STATUS_NOVOUCHER,"非未核准");

        paymentVoucherIds.stream()
                .forEach(paymentVoucherId -> {

                    //更新状态：未核准=》未过账
                    LambdaUpdateWrapper<PaymentVoucher> updateWrapper = new LambdaUpdateWrapper<>();
                    updateWrapper.eq(PaymentVoucher::getPaymentVoucherId,paymentVoucherId)
                            .set(PaymentVoucher::getPaymentVoucherStatus,PAYMENT_VOUCHER_STATUS_NOPAY)
                            .set(PaymentVoucher::getApprovedBy,nickName)
                            .set(PaymentVoucher::getApprovedTime,DateUtils.getNowDate())
                            .set(PaymentVoucher::getUpdateBy,nickName)
                            .set(PaymentVoucher::getUpdateTime,DateUtils.getNowDate());
                    paymentVoucherMapper.update(null,updateWrapper);

                    List<String> list = new ArrayList<>();
                    list.add(paymentVoucherId);

                    //更新付款单主表状态
                    updatePaymentMasterStatus(list);

                    //生成付款单日志
                    savePaymentVoucherLog(paymentVoucherId,"批量核准（单独付款）", nickName,"");

                    //生成水单并关联申请单
                    savePaymentWaterReceipt(list,nickName);
                });

    }
    /**
     * 查询日志
     */
    @Override
    public List<PaymentVoucherLogVo> selectPaymentVoucherLogList(PaymentVoucherLogVo paymentVoucherLog) {
        return paymentVoucherMapper.selectPaymentVoucherLogList(paymentVoucherLog);
    }
    /**
     * 驳回付款单
     */
    @Override
    @Transactional
    public void rejectPaymentVoucher(List<String> paymentVoucherIds, String rejectRemark, String nickName) {
        //检查是否为【未核准】状态
        CheckPaymentVoucherStatus(paymentVoucherIds,PAYMENT_VOUCHER_STATUS_NOVOUCHER,"非未核准");

        paymentVoucherIds.stream()
                .forEach(paymentVoucherId -> {
                    //付款单驳回
                    String paymentRequestId = rejectPaymentVoucherById(paymentVoucherId,rejectRemark);

                    //更新申请表状态为已驳回
                    PaymentRequest pr = new PaymentRequest();
                    pr.setPaymentRequestId(paymentRequestId);
                    pr.setUpdateBy(nickName);
                    pr.setPaymentReviewStatus(Constants.PAYMENT_REVIEW_STATUS_REJECTED);
                    pr.setPrepaymentRemark(rejectRemark);
                    paymentRequestProcessService.updatePaymentReviewStatusToPaymentVoucher(pr);

                    //生成付款单日志
                    savePaymentVoucherLog(paymentVoucherId,"驳回付款单", nickName,rejectRemark);
                });
    }

    /**
     * 上传水单
     */
    @Override
    @Transactional
    public int uploadWaterBillImg(PaymentWaterFormUpload formUpload, String nickName) {

        List<String> paymentVoucherIds = formUpload.getPaymentVoucherId();
        String waterBillImg = formUpload.getWaterBillImg();
        Boolean hasWaterBill = formUpload.getHasWaterBill();//true需要水单，false批量标记已付款

        if(hasWaterBill){
            if(StringUtils.isNull(waterBillImg)){
                throw new ServiceException("上传图片失败，请重新上传。");
            }
        }

        //检查是否上传了水单
        checkPaymentVoucherWater(paymentVoucherIds);

        //更新水单路径,付款单状态
        LambdaUpdateWrapper<PaymentVoucher> qw = new LambdaUpdateWrapper<>();
        qw.in(PaymentVoucher::getPaymentVoucherId,paymentVoucherIds);
        if (hasWaterBill) {
            qw.set(PaymentVoucher::getWaterBillImg, waterBillImg);
        }
        qw.set(PaymentVoucher::getPostingBy,nickName);
        qw.set(PaymentVoucher::getPostingTime,DateUtils.getNowDate());
        qw.set(PaymentVoucher::getPaymentVoucherStatus,PAYMENT_VOUCHER_STATUS_ISPAY);
        int rows = paymentVoucherMapper.update(null,qw);

        String logMsg = hasWaterBill ? "上传水单" : "批量标记已付款";

        paymentVoucherIds.stream()
                .forEach(paymentVoucherId -> {
                    //生成付款单日志
                    savePaymentVoucherLog(paymentVoucherId, logMsg, nickName, "");

                    //更新申请表
                    LambdaQueryWrapper<PaymentVoucher> qq = new LambdaQueryWrapper<>();
                    qq.eq(PaymentVoucher::getPaymentVoucherId,paymentVoucherId);
                    PaymentVoucher pvr = paymentVoucherMapper.selectOne(qq);
                    if(pvr == null){
                        throw new ServiceException("获取付款单款单信息失败。");
                    }
                    PaymentRequest pr = new PaymentRequest();
                    pr.setPaymentRequestId(pvr.getPaymentRequestId());
                    pr.setUpdateBy(nickName);
                    pr.setPaymentReviewStatus(Constants.PAYMENT_REVIEW_STATUS_APPROVED);
                    pr.setPrepaymentRemark(logMsg);
                    paymentRequestProcessService.updatePaymentReviewStatusToPaymentVoucher(pr);

                    //判断某采购订单是否已全部付款（全部上传水单且付款金额一致）
                    ProcuredOrders p = new ProcuredOrders();
                    p.setOrdersId(Long.valueOf(pvr.getProcuredOrderId()));
                    //hasWaterBill==true上传水单需要校验是否，hasWaterBill==false批量标记已付款不校验水单
                    if(hasWaterBill){
                        if(paymentVoucherMapper.isFullyPaid(pvr.getProcuredOrderId())){
                            //采购订单付款状态（0未申请付款，1部分申请付款，2已全部申请付款，3部分付款，4已全部付款）
                            p.setPaymentStatus("4");
                        }else{
                            p.setPaymentStatus("3");
                        }
                    }else{
                        if(paymentVoucherMapper.isFullyPaidNotWaterBill(pvr.getProcuredOrderId())){
                            //采购订单付款状态（0未申请付款，1部分申请付款，2已全部申请付款，3部分付款，4已全部付款）
                            p.setPaymentStatus("4");
                        }else{
                            p.setPaymentStatus("3");
                        }
                    }
                    procuredOrdersMapper.updateProcuredOrders(p);
                });
        //更新付款单主表状态
        updatePaymentMasterStatus(paymentVoucherIds);
        return rows;
    }
    /**
     *更新付款单付款状态
     */
    public void updatePaymentMasterStatus(List<String> paymentVoucherIds){
        paymentVoucherIds.stream()
                .forEach(paymentVoucherId -> {
            PaymentVoucher vo = paymentVoucherMapper.selectById(paymentVoucherId);

            String  paymentMasterId=  vo.getPaymentMasterId();
            // 2. 查询该主表下所有付款单的状态
            List<String> statuses = paymentVoucherMapper.selectVoucherStatusesByMasterId(vo.getPaymentMasterId());

            String paymentMasterStatus = calculatePaymentMasterStatus(statuses);

            PaymentMaster pm = new PaymentMaster();
            pm.setPaymentMasterId(paymentMasterId);
            pm.setPaymentMasterStatus(paymentMasterStatus);
            paymentMasterMapper.updateById(pm);
       });
    }
    /**
     *生成水单并关联申请单
     */
    public void savePaymentWaterReceipt(List<String> paymentVoucherIds, String nickName){
        //生成水单
        PaymentWaterReceipt pr = new PaymentWaterReceipt(IdUtils.fastSimpleUUID(),nickName,DateUtils.getNowDate());
        paymentWaterReceiptMapper.insert(pr);
        paymentVoucherIds.stream()
                .forEach(paymentVoucherId -> {

                    LambdaUpdateWrapper<PaymentVoucher> qw = new LambdaUpdateWrapper<>();
                    qw.eq(PaymentVoucher::getPaymentVoucherId,paymentVoucherId);
                    PaymentVoucher pvr = paymentVoucherMapper.selectOne(qw);
                    if(pvr == null){
                        throw new ServiceException("获取付款单款单信息失败。");
                    }
                    qw.set(PaymentVoucher::getWaterReceiptId,pr.getId());
                    paymentVoucherMapper.update(null,qw);

                    PaymentWaterReceiptVoucher pv = new PaymentWaterReceiptVoucher(IdUtils.fastSimpleUUID(),pr.getId(),paymentVoucherId);
                    paymentWaterReceiptVoucherMapper.insert(pv);
                    //生成付款单日志
                    savePaymentVoucherLog(paymentVoucherId,"生成水单", nickName,"");
                });
    }
    /**
     * 保存付款单主表
     */
    private PaymentMaster savePaymentMasterByPaymentRequestId(String paymentRequestId,String nickName){
        //获取供应商ID，货币ID
        VendorMonetaryDTO dto = paymentMasterMapper.selectVendorAndMonetary(paymentRequestId);
        if(null == dto){
            throw new ServiceException("获取供应商ID，货币ID失败。");
        }
        String vendorId = dto.getVendorId();
        String monetaryId = dto.getMonetaryId();
        AtomicInteger index = new AtomicInteger(0);
        //生成付款单
        String paymentMasterCode = generateMasterCode(index.getAndIncrement());
        PaymentMaster pm = new PaymentMaster(IdUtils.fastSimpleUUID(),paymentMasterCode,vendorId,monetaryId,nickName,DateUtils.getNowDate());
        paymentMasterMapper.insert(pm);
        return pm;
    }
    /**
     * 保存付款单明细
     */
    private void savePaymentVoucherByPaymentRequestId(List<String>paymentRequestIds, String nickName, PaymentMaster pm){
        AtomicReference<BigDecimal> amountDue = new AtomicReference<>(BigDecimal.ZERO);

        paymentRequestIds.stream()
            .forEach(paymentRequestId -> {

                LambdaQueryWrapper<PaymentRequest> qw = new LambdaQueryWrapper<>();
                qw.in(PaymentRequest::getPaymentRequestId,paymentRequestId);
                PaymentRequest pr = paymentRequestMapper.selectOne(qw);
                if(pr == null){
                    throw new ServiceException("获取申请款单信息失败。");
                }

                //更新申请表申请状态
                pr.setPaymentStatus(PAYMENT_STATUS_ISVOUCHER);
                paymentRequestService.saveOrUpdate(pr);

                //生成付款单明细
                String procuredOrderId = pr.getProcuredOrderId();
                String paymentVoucherType = pr.getPaymentType();
                String paymentVoucherStatus = PAYMENT_VOUCHER_STATUS_NOVOUCHER;

                BigDecimal payableAmount = pr.getPayableAmount();
                BigDecimal prepaymentAmount = pr.getPrepaymentAmount();
                BigDecimal result = (payableAmount != null && payableAmount.compareTo(BigDecimal.ZERO) > 0)
                        ? payableAmount
                        : prepaymentAmount;

                PaymentVoucher pv = new PaymentVoucher(IdUtils.fastSimpleUUID(), pm.getPaymentMasterId(), procuredOrderId, paymentRequestId,
                        paymentVoucherStatus, paymentVoucherType,result, pr.getPrepaymentRemark(), nickName, DateUtils.getNowDate());
                paymentVoucherMapper.insert(pv);

                //生成付款单日志
                savePaymentVoucherLog(pv.getPaymentVoucherId(),"生成付款单", nickName,"");

                amountDue.updateAndGet(current -> current.add(
                        safeAdd(pr.getPayableAmount(), pr.getPrepaymentAmount())
                ));
            });
        pm.setAmountDue(amountDue.get());
        paymentMasterMapper.updateById(pm);
    }
    /**
     * 撤回采购计划
     * @param procuredPlan
     * @return
     */
    @Override
    @Transactional
    public int revokeProcuredPlan(ProcuredPlan procuredPlan, String nickName, Long userId, String componentPath) {

        // 1. 查询该采购计划下是否存在采购订单
        ProcuredOrders p = new ProcuredOrders();
        p.setPlanId(procuredPlan.getPlanId());
        List<ProcuredOrders> procuredOrdersList= procuredOrdersMapper.selectByPlanId(p);
        String revokeRemark = procuredPlan.getRevokeRemark();
        String deleteStatus = "1";//已撤回

        // 2. 存在采购订单的情况
        if (procuredOrdersList != null && !procuredOrdersList.isEmpty()) {
            for (ProcuredOrders order : procuredOrdersList) {
                Long orderId = order.getOrdersId();

                //采购订单是否有快递单号
                String expressNumber = order.getExpressNumber();
                if(StringUtils.isNotEmpty(expressNumber)){
                    throw new RuntimeException("采购单号：" + order.getOrdersNumber() + " 已有快递单号，无法撤回采购计划！");
                }

                //采购订单是否关联已收货
                LambdaQueryWrapper<Receipt> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Receipt::getOrdersId, orderId);
                boolean exists = receiptMapper.selectCount(queryWrapper) > 0;
                if (exists) {
                    throw new RuntimeException("采购单号：" + order.getOrdersNumber() + " 已有收货单，无法撤回采购计划！");
                }

                // 构造查询条件：根据采购订单ID查付款申请单列表
                PaymentRequest paymentQuery = new PaymentRequest();
                paymentQuery.setProcuredOrderId(String.valueOf(orderId));
                List<PaymentRequest> requestList = paymentRequestMapper.selectPaymentRequestList(paymentQuery);

                // 遍历所有付款申请单，检查是否有已上传水单
                if (requestList != null && !requestList.isEmpty()) {
                    for (PaymentRequest request : requestList) {
                        String requestId = request.getPaymentRequestId();
                        PaymentVoucherVo voucher = paymentVoucherMapper.selectByPaymentRequestId(requestId);
                        if(voucher != null && voucher.getPaymentVoucherStatus().equals(PAYMENT_VOUCHER_STATUS_ISLOCK)){
                            throw new RuntimeException("采购单号：" + voucher.getOrdersNumber() + " 锁定付款，无法撤回采购计划！");
                        }
                        if (voucher != null && voucher.getWaterBillImg() != null && !voucher.getWaterBillImg().trim().isEmpty()) {
                            throw new RuntimeException("采购单号：" + voucher.getOrdersNumber() + " 已上传水单，无法撤回采购计划！");
                        }
                        //逻辑删除付款单
                        if (voucher != null){
                            PaymentVoucher pv = new PaymentVoucher();
                            pv.setPaymentVoucherId(voucher.getPaymentVoucherId());
                            pv.setDeleteStatus(deleteStatus);
                            pv.setRevokeRemark(procuredPlan.getRevokeRemark());
                            paymentVoucherMapper.updateById(pv);

                            //插入撤回日志
                            savePaymentVoucherLog(pv.getPaymentVoucherId(),"采购计划撤回", nickName, revokeRemark);
                        }
                        //逻辑删除申请款
                        request.setRevokeRemark(revokeRemark);
                        request.setDeleteStatus(deleteStatus);
                        paymentRequestMapper.updateById(request);
                        //插入撤回日志
                        savePaymentRequestLog(request.getPaymentRequestId(),"3",nickName, revokeRemark);
                    }
                }
                //清除已转数量
                procuredProductMapper.resetProcuredProductByPlanId(p.getPlanId());

                //逻辑删除采购订单
                order.setRevokeRemark(revokeRemark);
                order.setDeleteStatus(deleteStatus);
                procuredOrdersMapper.updateProcuredOrders(order);
            }
        }

        // 3. 不存在采购订单，修改采购订单状态，重置审核流程，插入撤回日志
        Long planId = procuredPlan.getPlanId();
        procuredPlan.setPlanStatus("0");//未审核
        procuredPlan.setDeleteStatus(Constants.PAYMENT_REQUEST_PROCESS_STATUS_PENDING);
        procuredPlan.setActualAmount(BigDecimal.ZERO); // 清空采购金额
        procuredPlan.setRevokeRemark(revokeRemark);
        //重置审核流程
        String reviewerId = resetPlanProcess(planId,userId,componentPath);
        procuredPlan.setReviewerUserId(Long.valueOf(reviewerId));

        //插入撤回日志
        saveProcuredPlanLog(String.valueOf(planId),"3",nickName, revokeRemark);

        return procuredPlanMapper.updateById(procuredPlan);
    }
    /**
     * 标记锁定付款单
     */
    @Override
    @Transactional
    public void tagLockPaymentVoucher(List<String> paymentVoucherIds, String nickName) {
        //检查是否为【未过账】状态
        CheckPaymentVoucherStatus(paymentVoucherIds,PAYMENT_VOUCHER_STATUS_NOPAY,"非未过账");
        //更新状态：未过账=》锁定中
        LambdaUpdateWrapper<PaymentVoucher> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(PaymentVoucher::getPaymentVoucherId,paymentVoucherIds)
                .set(PaymentVoucher::getPaymentVoucherStatus,PAYMENT_VOUCHER_STATUS_ISLOCK);
        paymentVoucherMapper.update(null,updateWrapper);
        //插入日志
        paymentVoucherIds.stream()
                .forEach(paymentVoucherId -> {
                    //生成付款单日志
                    savePaymentVoucherLog(paymentVoucherId,"锁定付款", nickName,"");
                });

    }

    //重置审核流程
    @Transactional
    public String resetPlanProcess(Long planId, Long userId, String componentPath ){

        SysMenu sysMenu = sysMenuMapper.selectMenuByComponent(componentPath);
        if(sysMenu == null){
            throw new ServiceException("获取菜单ID失败，请刷新页面重新操作。");
        }

        //校验当前菜单和用户是否绑定
        String templateId= templateMapper.findTemplateIdByUserIdAndMenuId(userId, sysMenu.getMenuId());
        if(StringUtils.isNull(templateId)||templateId == null){
            throw new ServiceException("未匹配到对应的审核模板，请联系人事匹配后再操作。");
        }

        //获取模板详情
        List<TemplateDetail> templateDetails = templateDetailService.getTemplateDetailList(templateId);
        if(templateDetails.isEmpty()||templateDetails == null){
            throw new ServiceException("获取模板详情失败。");
        }
        TemplateDetail firstDetail = templateDetails.get(0);
        String reviewerUserId = firstDetail.getReviewerId();

        //审核表插入审核流程记录
        procuredPlanProcessService.insertProcuredPlanProcessQuash(String.valueOf(planId), templateDetails, userId);

        return reviewerUserId;
    }
    /**
     * 驳回付款单
     */
    private String rejectPaymentVoucherById(String paymentVoucherId, String rejectRemark){
        LambdaUpdateWrapper<PaymentVoucher> qw = new LambdaUpdateWrapper<>();
        qw.eq(PaymentVoucher::getPaymentVoucherId,paymentVoucherId);
        PaymentVoucher pvr = paymentVoucherMapper.selectOne(qw);
        if(pvr == null){
            throw new ServiceException("获取付款单款单信息失败。");
        }
        qw.set(PaymentVoucher::getRejectRemark,rejectRemark);
        qw.set(PaymentVoucher::getPaymentVoucherStatus,PAYMENT_VOUCHER_STATUS_ISREJECT);
        paymentVoucherMapper.update(null,qw);

        return pvr.getPaymentRequestId();
    }
    /**
     * 检查是否生成了付款单
     */
    private boolean  checkPaymentVoucher(List<String> paymentRequestIds) {
        QueryWrapper<PaymentVoucher> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("payment_request_id", paymentRequestIds);
        List<PaymentVoucher> paymentVouchers = paymentVoucherMapper.selectList(queryWrapper);
        return paymentVouchers != null && !paymentVouchers.isEmpty();
    }
    /**
     * 生成审核流程日志
     */
    private void saveProcuredPlanLog(String procuredPlanId, String logStatus, String nickName, String logRemark){
        ProcuredPlanLog pp = new ProcuredPlanLog(IdUtils.fastSimpleUUID(),procuredPlanId,
                logStatus,nickName,logRemark,DateUtils.getNowDate());
        procuredPlanLogMapper.insert(pp);
    }
    /**
     * 生成申请款日志
     */
    private void savePaymentRequestLog(String paymentRequestId, String logStatus, String nickName, String logRemark){
        PaymentRequestLog pr = new PaymentRequestLog(IdUtils.fastSimpleUUID(),paymentRequestId,
                logStatus,nickName,logRemark,DateUtils.getNowDate());
        paymentRequestLogMapper.insert(pr);
    }
    /**
     * 生成付款单日志
     */
    private void savePaymentVoucherLog(String paymentVoucherId, String logMessage, String nickName, String logRemark){
        PaymentVoucherLog pvl = new PaymentVoucherLog(IdUtils.fastSimpleUUID(),paymentVoucherId,
                logMessage,nickName,DateUtils.getNowDate(),logRemark);
        paymentVoucherLogMapper.insert(pvl);
    }
    /**
     * 校验申请单状态
     * paymentVoucherStatus:0未核准，1未过账，2已过账，3已驳回
     */
    private void CheckPaymentVoucherStatus(List<String> paymentVoucherIds,String paymentVoucherStatus, String message){
        LambdaQueryWrapper<PaymentVoucher> qw = new LambdaQueryWrapper<>();
        qw.in(PaymentVoucher::getPaymentVoucherId,paymentVoucherIds);
        qw.eq(PaymentVoucher::getPaymentVoucherStatus,paymentVoucherStatus);
        qw.eq(PaymentVoucher::getDeleteStatus,"0");
        List<PaymentVoucher> result = paymentVoucherMapper.selectList(qw);

        if (result.size() != paymentVoucherIds.size()) {
            throw new ServiceException("所选记录含有【"+message+"】的数据，请刷新页面重新选择");
        }

    }
    /**
     * 检查是否上传了水单
     */
    private void checkPaymentVoucherWater(List<String> paymentVoucherIds) {
        LambdaQueryWrapper<PaymentVoucher> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(PaymentVoucher::getPaymentVoucherId, paymentVoucherIds);
        queryWrapper.eq(PaymentVoucher::getPaymentVoucherStatus,PAYMENT_VOUCHER_STATUS_NOPAY);
        queryWrapper.isNull(PaymentVoucher::getWaterBillImg);
        List<PaymentVoucher> result = paymentVoucherMapper.selectList(queryWrapper);
        if (result.size() != paymentVoucherIds.size()) {
            throw new ServiceException("所选记录含有【已过账】的数据，请刷新页面重新选择");
        }
    }
    /**
     * 付款单明细表状态：0未核准，1未过账，2已过账，3已驳回
     * 返回付款单主表状态：0未核准，1部分核准，2未过账，3部分过账，4已过账，5驳回，6锁定中
     * @return
     */
    private String calculatePaymentMasterStatus(List<String> statuses) {
        if (statuses.stream().allMatch("2"::equals)) return "4";
        if (statuses.stream().allMatch("1"::equals)) return "2";
        if (statuses.contains("0")) return "1";
        if (statuses.contains("2")) return "3";
        return "0";
    }
    /**
     * 生成随机数
     * @return
     */
    private String generateMasterCode(int size) {
        // 获取当前日期
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String currentDate = dateFormat.format(new Date());

        // 获取序列号
        String paymentMasterOrder = paymentVoucherMapper.selectPaymentMasterCode();
        String randomNumber;
        // ...根据自己的业务逻辑实现获取序列号的方法
        if(StringUtils.isEmpty(paymentMasterOrder)){
            randomNumber = Constants.RANDOM_NUMBERS;
        }else{
            randomNumber = String.format("%04d", (NumberUtils.parseNumber(paymentMasterOrder.substring(10),Long.class)+(size+1)));
        }

        // 拼接生成的代码
        String code = Constants.CODE_SLIPS + currentDate + randomNumber;

        return code;
    }

    //叠加金额
    private static BigDecimal safeAdd(BigDecimal... values) {
        BigDecimal result = BigDecimal.ZERO;
        for (BigDecimal value : values) {
            if (value != null) {
                result = result.add(value);
            }
        }
        return result;
    }

}
